export default class HeartsFlow {
	constructor(data) {
		let self = data.that;
	    uni.createSelectorQuery().in(self)
	    .select(data.canvasEl)
	    .fields({
	        node: true,
			size: true
	    })
	    .exec(res => {
			const canvas = res[0].node;
			this.el = canvas;
			this.lastFrameTime = 0;
			this.w = 200;
			this.h = 400;
			this.ctx = this.el.getContext('2d');
			this.colors = [
			'255, 137, 164', //'#FF89A4',
			'239, 121, 138', //'#EF798A',
			'255, 77, 128', //'#FF4D80',
			'249, 42, 130', //'#F92A82',
			'168, 67, 233', // #A843E9,
			'242, 61, 59', // #F23D3B,
			'253, 202, 60', //#FDCA3C,
			'228, 56, 181', //#E438B5,
			];
			this.heartsAmount = data.amount;
			this.heartsList = [];
			this.isAnimate = false;
			this.raf = null;
			this.animate = this.animate.bind(this);
			this.paintHeart = this.paintHeart.bind(this);
			this.stopAnimation = this.stopAnimation.bind(this,self);
			this.init();
		});
  }
  
  getRandomColor() {
    return this.colors[Math.floor(Math.random() * this.colors.length)];
  }
  getRandom(min, max) {
    return Math.floor(Math.random() * (max - min) + min);
  }
  setHeartsList() {
    let arr = [];
    for (let i = 0; i < this.heartsAmount; i++) {
		let currentSize = this.getRandom(10, 15);
		let dt = {
			x: this.w / 2,
			y: this.h,
			bx: this.w / 2,
			by: this.h,
			pos: this.h,
			_osp: this.getRandom(200, 400) / 100,
			osp: this.getRandom(11, 12) / 10,
			vsp: this.getRandom(currentSize, currentSize + i * 2) / 1000,
			size: currentSize,
			color: this.getRandomColor(),
			alfa: 1 ,
		};

      arr.push(dt);
    }
    this.heartsList = [...this.heartsList, ...arr];
  }
  getCoordinates({ x, y, size, color, bx, by, _osp, osp, vsp, pos, alfa }) {
    return {
      xst: x,
      yst: y + size / 2,
      x0: x - size / 1.4,
      y0: y + size / 4,
      x1: x - size / 1.3,
      y1: y - size / 1.3,
      _x0: x + size / 1.4,
      _y0: y + size / 4,
      _x1: x + size / 1.3,
      _y1: y - size / 1.3,
      xfn: x,
      yfn: y - size / 3,
      bx: bx,
      by: by,
      _osp: _osp,
      osp: osp,
      vsp: vsp,
      pos: pos,
      alfa: alfa,
      size: size,
      color: color };

  }
  paintHeart({ xst, yst, x0, y0, _x0, _y0, x1, y1, _x1, _y1, xfn, yfn, color, alfa }) {
    this.ctx.globalCompositeOperation = "lighter";
    this.ctx.beginPath();
    this.ctx.moveTo(xst, yst);
    this.ctx.bezierCurveTo(x0, y0, x1, y1, xfn, yfn);
    this.ctx.moveTo(xst, yst);
    this.ctx.bezierCurveTo(_x0, _y0, _x1, _y1, xfn, yfn);
    this.ctx.fillStyle = `rgba(${color}, ${alfa})`;
    this.ctx.strokeStyle = `rgba(${color}, ${alfa})`;
    this.ctx.fill();
    this.ctx.stroke();
    this.ctx.closePath();
  }
  mutateData() {
    this.heartsList = this.heartsList.map(item => {
      let pos = item.pos - 0.05;
      let x = item.x + Math.sin(pos * item._osp) * ((pos - item.by) / item.osp);
      let y = pos + (pos - item.by) / item.vsp * 1.6;
      let alfa = this.normalize0between1(0, this.h, y).toFixed(1);
      return {
        ...item, x: x, y: y, pos: pos, alfa: alfa };

    });
    this.heartsList = this.heartsList.filter(item => item.y > 0);
  }
	normalize0between1(min, max, value) {
		return (value - min) / (max - min);
	}
	setCanvas() {
		this.el.width = this.w;
		this.el.height = this.h;
	}
	startAnimation() {
		if (!this.isAnimate) {
			this.isAnimate = true;
			console.log('start animation');
			this.setHeartsList();
			this.animate();
		} else {
			this.setHeartsList();
		}
	}
	stopAnimation(self) {
		this.isAnimate = false;
		console.log('stop animation');
		self.showCanvas = false;
		this.abortAnimationFrame(this.raf);
	}
	animate() {

		this.ctx.clearRect(0, 0, this.w, this.h);

		if (this.isAnimate) {
		  for (let i = 0, len = this.heartsList.length; i < len; i++) {
			let hrt = this.getCoordinates(this.heartsList[i]);
			this.paintHeart(hrt);
		  }
		  this.mutateData();
		}
		
		this.raf = this.doAnimationFrame(this.animate);

		if (this.heartsList.length === 0 && this.isAnimate) {
		  this.stopAnimation();
		}
  }
  
	// 模拟 requestAnimationFrame
	doAnimationFrame(callback) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16 - (currTime - this.lastFrameTime));
      var id = setTimeout(function () { callback(currTime + timeToCall); }, timeToCall);
      this.lastFrameTime = currTime + timeToCall;
      return id;
	};
	
	// 模拟 cancelAnimationFrame
	abortAnimationFrame(id) {
		clearTimeout(id)
	}
  
  init() {
    this.setCanvas();
    this.setHeartsList();
    this.animate();
  }
}